/**
 * JavaDistiller Refactoring API.
 * <p>
 * 
 * @author sleroy
 * @version $LastChangedRevision: 1833 $ $LastChangedDate: 2010-07-07 13:50:55 +0200 (mer., 07 juil. 2010) $
 * @since 27 mars 2009
 * @copyright Copyright (C) 2008-2009 IRISA/INRIA Property.
 */

package com.tocea.formation.xml.utils;


import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;


/**
 * This utility class provides some methods to manipulate XML representations.
 * 
 * @copyright Copyright (c) 2008 INRIA/Irisa
 */
public final class XmlUtils
{
    
    /**
     * This field describes
     */
    private static final String EXCEPTION_HAPPENED = "Exception happened ";             //$NON-NLS-1$
                                                                                         
    
    /**
     * This method marshalles a structure into a xml.
     * 
     * @param _object
     *            the object, root of the XML
     * @param _outputFile
     *            the output file
     * @throws JAXBException
     */
    public static void marshallXML(final Object _object, final java.io.File _outputFile) throws JAXBException {
    
        String packageName;
        if (_object instanceof JAXBElement) {
            @SuppressWarnings("rawtypes")
            final Object value = ((JAXBElement) _object).getValue();
            if (value == null) {
                System.err.println("Cannot guess which package name is it."); //$NON-NLS-1$
                return;
            }
            packageName = value.getClass().getPackage().getName();
        } else {
            packageName = _object.getClass().getPackage().getName();
        }
        marshallXML(_object, _outputFile, packageName);
    }
    
    /**
     * This method marshalles a structure into a xml.
     * 
     * @param _object
     *            the object, root of the XML
     * @param _outputFile
     *            the output file
     * @param _packageName
     *            the name of the package
     * @throws JAXBException
     */
    public static void marshallXML(final Object _object, final java.io.File _outputFile, final String _packageName) throws JAXBException {
    
        final JAXBContext context = JAXBContext.newInstance(_packageName);
        final Marshaller createMarshaller = context.createMarshaller();
        createMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        createMarshaller.marshal(_object, _outputFile);
    }
    
    /**
     * This method unmarshall an xml file from a definition.
     * 
     * @param <T>
     *            the type of element expected in return.
     * @param _stream
     *            the intput stream
     * @param _objectFactory
     *            the package definition of the xml schema
     * @return the root element or null in case of error.
     * @since 16 juin 2010
     * @author sleroy
     */
    @SuppressWarnings("unchecked")
    public static <T> T unmarshallXML(final InputStream _stream, final Class<?> _objectFactory) {
    
        if (_stream == null) {
            System.err.println("No information received."); //$NON-NLS-1$
            return null;
        }
        T res = null;
        final ClassLoader currentCL = Thread.currentThread().getContextClassLoader();
        try {
            final ClassLoader classLoader = _objectFactory.getClassLoader();
            Thread.currentThread().setContextClassLoader(classLoader);
            final JAXBContext jc = JAXBContext.newInstance(_objectFactory.getPackage().getName());
            final Unmarshaller unmarshaller = jc.createUnmarshaller();
            final Object unmarshal = unmarshaller.unmarshal(_stream);
            if (unmarshal instanceof JAXBElement) {
                res = ((JAXBElement<T>) unmarshal).getValue();
            } else {
                res = (T) unmarshal;
            }
        } catch (final Throwable e) {
            /* Produces the exception description in the log. */
            System.err.println(e);
            e.printStackTrace();
            res = null;
        } finally {
            Thread.currentThread().setContextClassLoader(currentCL);
            try {
                _stream.close();
            } catch (final Exception e) {
                System.err.println(e);
                e.printStackTrace();
            }
        }
        return res;
    }
    
    /**
     * This method unmarshall an xml file from a definition.
     * 
     * @param <T>
     *            the type of element expected in return.
     * @param _file
     *            the file
     * @param _objectFactory
     *            the package definition of the xml schema
     * @return the root element or null in case of error.
     * @since 16 juin 2010
     * @author sleroy
     */
    @SuppressWarnings("unchecked")
    public static <T> T unmarshallXML(final URL _file, final Class<?> _objectFactory) {
    
        if (_file == null) {
            return null;
        }
        T res = null;
        try {
            res = (T) unmarshallXML(_file.openStream(), _objectFactory);
        } catch (final IOException e) {
            System.err.println(EXCEPTION_HAPPENED);
            e.printStackTrace();
        }
        
        return res;
    }
    
    /**
     * Private Deprecated Constructor. (Utility class)
     */
    @Deprecated
    private XmlUtils() {
    
        // Private Constructor
    }
}
